#include <stdlib.h>
#include <assert.h>
#include "cJSON.h"
#include "hrd_core.h"
#include "hrd_coord.h"
#include "hrd_logger.h"
#include "hrd_bitmask.h"
#include "hrd_coordinate_list_loader.h"


static hrd_bitmask_t loadBoundary(cJSON *base_json)
{
    int16_t coordinate_number = 0;
    struct coordinate_s coordinate_list[MAX_OBJECT_NUMBER] = {0};
    cJSON *boundary_json = NULL;

    boundary_json = cJSON_GetObjectItemCaseSensitive(base_json, "boundary");
    if (boundary_json == NULL) {
        return 0;
    }

    coordinate_number = HrdCoordinateListLoader_Load(boundary_json, coordinate_list, MAX_OBJECT_NUMBER);
    if (coordinate_number == LOAD_LIST_FAILURE) {
        LOG_WARNING("Error occur while loading boundary coordinates. Default boundary will be used.");
        return 0;
    }

    return HrdCoord_CoordinateListToBitmask(coordinate_list, coordinate_number);
}


static hrd_bitmask_t loadGoal(cJSON *base_json)
{
    int16_t coordinate_number = 0;
    struct coordinate_s coordinate_list[MAX_OBJECT_NUMBER] = {0};
    cJSON *goal_json = NULL;

    goal_json = cJSON_GetObjectItemCaseSensitive(base_json, "goal");
    if (goal_json == NULL) {
        LOG_FATAL("Unable to get goal.");
        return 0;
    }

    coordinate_number = HrdCoordinateListLoader_Load(goal_json, coordinate_list, MAX_OBJECT_NUMBER);
    if (coordinate_number == LOAD_LIST_FAILURE) {
        LOG_FATAL("Error occur while loading goal coordinates.");
        return 0;
    }

    return HrdCoord_CoordinateListToBitmask(coordinate_list, coordinate_number);
}


hrd_problem_t *HrdProblemLoader_Load(cJSON *base_json, hrd_problem_t *hrd_problem)
{
    assert(base_json != NULL);
    assert(hrd_problem != NULL);

    hrd_bitmask_t boundary;
    hrd_bitmask_t goal;

    boundary = loadBoundary(base_json);
    goal = loadGoal(base_json);
    if (goal == 0) {
        LOG_FATAL("Error occur while loading goal.");
        return NULL;
    }

    HrdBitmask_SetBoundary(hrd_problem->bitmask_list, boundary);
    if (HrdBitmask_IsGoalValid(hrd_problem->bitmask_list, goal) == false) {
        LOG_FATAL("Goal is invalid.");
        return NULL;
    }

    hrd_problem->goal = goal;

    return hrd_problem;
}
